#![allow(missing_docs)]

use semx_bitops::{
    BITS_PER_LONG, bit, bit_ull, bits_to_longs, change_bit, clear_bit, deposit32, deposit64,
    extract8, extract16, extract32, extract64, find_first_bit, find_first_zero_bit, find_last_bit,
    find_next_bit, find_next_zero_bit, half_shuffle32, half_shuffle64, half_unshuffle32,
    half_unshuffle64, make_64bit_mask, set_bit, test_and_change_bit, test_and_clear_bit,
    test_and_set_bit, test_bit,
};

#[test]
fn bitops_test() {
    #[cfg(target_pointer_width = "64")]
    assert_eq!(BITS_PER_LONG, 64);

    #[cfg(target_pointer_width = "32")]
    assert_eq!(BITS_PER_LONG, 32);

    assert_eq!(1, bit(0));
    assert_eq!(2, bit(1));
    assert_eq!(4, bit(2));
    assert_eq!(0x10000000, bit(28));

    let bits = bit(0);
    assert_eq!(bits, 1);
    let bits = bit(31);
    assert_eq!(bits, 0x80000000);

    assert_eq!(1 << 63, bit_ull(63));

    assert_eq!(1, semx_bitops::bit_mask(0));
    assert_eq!(8, semx_bitops::bit_mask(3));
    assert_eq!(16, semx_bitops::bit_mask(4));

    let bit_mask = semx_bitops::bit_mask(64);
    assert_eq!(bit_mask, 1);

    let bit_word = semx_bitops::bit_word(2);
    assert_eq!(bit_word, 0);

    let bit_word = semx_bitops::bit_word(65);
    assert!(bit_word == 1 || bit_word == 2);

    assert_eq!(bits_to_longs(1), 1);
    assert_eq!(bits_to_longs(31), 1);

    assert_eq!(make_64bit_mask(0, 1), 1);
    assert_eq!(make_64bit_mask(0, 2), 0b11);
    assert_eq!(make_64bit_mask(1, 3), 0b1110);

    let mut bit = [0b101010111101; 1];
    set_bit(1, &mut bit);
    assert_eq!(bit[0], 0b101010111111);
    clear_bit(5, &mut bit);
    assert_eq!(bit[0], 0b101010011111);
    change_bit(5, &mut bit);
    assert_eq!(bit[0], 0b101010111111);

    let var = test_and_set_bit(6, &mut bit);
    assert!(!var);
    assert_eq!(bit[0], 0b101011111111);

    let var = test_and_clear_bit(1, &mut bit);
    assert!(var);
    assert_eq!(bit[0], 0b101011111101);

    let var = test_and_clear_bit(1, &mut bit);
    assert!(!var);
    assert_eq!(bit[0], 0b101011111101);

    let var = test_and_change_bit(2, &mut bit);
    assert!(var);
    assert_eq!(bit[0], 0b101011111001);

    let var = test_and_change_bit(2, &mut bit);
    assert!(!var);
    assert_eq!(bit[0], 0b101011111101);

    assert!(test_bit(3, &bit));
    assert!(!test_bit(1, &bit));

    let mut bit = [0b101010111101, 0b0000];
    set_bit(64, &mut bit);
    assert_eq!(bit[1], 1);
    let index = find_last_bit(&bit, 128);
    assert_eq!(index, 64);

    let bit = [0b101010111101, 0b0000];
    let index = find_next_bit(&bit, 128, 0);
    assert_eq!(index, 0);
    let index = find_next_bit(&bit, 128, 1);
    assert_eq!(index, 2);
    let index = find_next_bit(&bit, 128, 6);
    assert_eq!(index, 7);

    let index = find_next_zero_bit(&bit, 128, 0);
    assert_eq!(index, 1);
    let index = find_next_zero_bit(&bit, 128, 2);
    assert_eq!(index, 6);

    assert_eq!(find_first_bit(&bit, 128), 0);
    assert_eq!(find_first_zero_bit(&bit, 128), 1);

    let value = 0xc4u8;
    let ex = extract8(value, 1, 2);
    assert_eq!(ex, 2);

    let value = 0x18c4u16;
    let ex = extract16(value, 4, 4);
    assert_eq!(ex, 0xc);

    let value = 0x8000008Eu32;
    let ex = extract32(value, 1, 3);
    assert_eq!(ex, 7);

    let value = 0x1a000f7000cu64;
    let ex = extract64(value, 32, 8);
    assert_eq!(ex, 0xa0);

    let value = 0x8000008Eu32;
    let value = deposit32(value, 4, 2, 1);
    assert_eq!(value, 0x8000009E);

    let value = 0x1a000f7000cu64;
    let value = deposit64(value, 32, 2, 3);
    assert_eq!(value, 0x1a300f7000c);

    let value = 0b1111;
    let value = half_shuffle32(value);
    assert_eq!(value, 0b1010101);
    let value = half_unshuffle32(value);
    assert_eq!(value, 0b1111);

    let value: u64 = 0b1111_0000_0000_0000_0000;
    let value = half_shuffle64(value);
    assert_eq!(value, 0x5500000000);
    let value = half_unshuffle64(value);
    assert_eq!(value, 0b1111_0000_0000_0000_0000);
}
